package com.pactera.redisrelated.redis;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
@Slf4j
public class RedisIdGenerator {

    private static final String ID_KEY_PREFIX = "id:generator:";

    private static final long BEGIN_TIMESTAMP = 1640995200L;

    private static int COUNT_BITS = 32;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public Long nextUUID() {

        LocalDateTime now = LocalDateTime.now();
        // 当前时间得秒数 - 初始秒数
        long time = now.toEpochSecond(ZoneOffset.UTC) - BEGIN_TIMESTAMP;

        String format = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));

        RedisAtomicLong counter = new RedisAtomicLong(ID_KEY_PREFIX + format, stringRedisTemplate.getConnectionFactory());
        long id = counter.getAndIncrement();

        return time << COUNT_BITS | id;

    }

    private ExecutorService executorService = Executors.newFixedThreadPool(20);
    @SneakyThrows
    public void test(){
         int thradNum = 500, forEachNum = 20;
        CountDownLatch countDownLatch = new CountDownLatch(thradNum);
        long start = System.currentTimeMillis();

        Callable task = new Task(countDownLatch, forEachNum);


        HashSet<Long> set = new HashSet<>();
        for (int i = 0; i < thradNum; i++) {
            set.addAll((HashSet<Long>) executorService.submit(task).get());
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("期望id数量：{}；实际id数量：{}；执行时间： {}", thradNum * forEachNum, set.size(), (System.currentTimeMillis() - start));
    }

    class Task implements Callable<HashSet<Long>> {
        CountDownLatch countDownLatch ;
        int forEachNum ;

        public Task(CountDownLatch countDownLatch, int forEachNum) {
            this.countDownLatch = countDownLatch;
            this.forEachNum = forEachNum;
        }

        @Override
        public HashSet<Long> call() throws Exception {
            HashSet<Long> ids = new HashSet<>();
            for (int i = 0; i < forEachNum; i++) {
                 ids.add(nextUUID());
            }
            countDownLatch.countDown();
            return ids;
        }
    }




}
